﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.Xml.Serialization;
using System.IO;
using System.Diagnostics;
using System.Threading;

namespace Stone
{
    public partial class FormMain : Form
    {
        //Variables
        private bool mousePressed = false;
        private Point mousePositionOnMouseDown = new Point();
        private Skin skin = new Skin();
        private Skin_Screen currentScreen_ = new Skin_Screen();
        private Skin_Button currentButton_ = null;
        private Graphics FormMainGraphics = null;
        private Rectangle FormMainRectangle = new Rectangle(0, 0, 800, 480);
        private Image RenderedScreenImage = null;
        private bool RenderedScreenImage_ToCompletelyRepaint = false;
        
        //Modules
        Module_Radio_Silabs moduleRadioSilabs = new Module_Radio_Silabs();
        Module_Gps_Osm moduleGpsOsm = new Module_Gps_Osm();
        Module_Cam moduleCam = new Module_Cam();
        Module_Web moduleWeb = new Module_Web();

        //Gps
        public GPSHandler GpsHandler;

        //Skin
        private Skin_Screen currentScreen
        {
            get
            {
                return currentScreen_;
            }
            set
            {
                DeApplyScreen(currentScreen_);
                currentScreen_ = value;
                ApplyScreen();
            }
        }
        
        //Constructor
        public FormMain()
        {
            InitializeComponent();

            Size monitorResolution = SystemInformation.PrimaryMonitorSize;

            if ((monitorResolution.Width == 800) && (monitorResolution.Height == 480))
            {
                this.TopMost = true;
                this.FormBorderStyle = FormBorderStyle.None;
            }

            //Initialize GPS handler
            GpsHandler = new GPSHandler(this);
            //Hook up GPS data events to a handler
            GpsHandler.NewGPSFix += new GPSHandler.NewGPSFixHandler(this.GPSEventHandler);
        }

        //Main events
        private void GPSEventHandler(object sender, GPSHandler.GPSEventArgs e)
        {            
            moduleGpsOsm.ReceiveNMEA(GpsHandler, e);            
        }
        private void FormMain_Load(object sender, EventArgs e)
        {
            Settings.LoadSettings();
            FormMainGraphics = this.CreateGraphics();
            FormMainRectangle = new Rectangle(0, 0, 800, 480);
            LoadSkin();
            timerSystemPerformance.Start();
            //LoadPlugins(); 
            //Plugin plugintest = (Plugin)Activator.CreateInstance( "AssemblyName", "TypeName", null );

            //Assembly MyDALL = Assembly.Load(@"C:\Users\Riky\Desktop\Stone KKK\Stone_2\Stone_2\Stone_2\bin\Debug\Plugins\Radio\Plugin.dll"); //DALL name of your assembly 
            //Type MyLoadClass = MyDALL.GetType("Stone.Plugin_Radio"); // name of your class 
            //object obj = Activator.CreateInstance(MyLoadClass);
            //Plugin plugintest = (Plugin)obj;
            //Log(plugintest.Name);    

            
            //GpsHandler.EnableEmulate(Settings.NMEA_path);  
            GpsHandler.Start(Settings.GPS_ComPort, int.Parse(Settings.GPS_ComPort_Baudrate));
            Thread.Sleep(3000);
            
            if (!GpsHandler.IsPortOpen)
            {
                MessageBox.Show("Error opening " + Settings.GPS_ComPort + " at " + Settings.GPS_ComPort_Baudrate + " baudrate. Verify your settings!\nStone will emulate GPS antenna...");
                //moduleGpsOsm.PointTo(new PointF(9.236975f, 45.491090f));  
                GpsHandler.Stop();
                GpsHandler.EnableEmulate(Settings.NMEA_path);
                GpsHandler.Start(Settings.GPS_ComPort, int.Parse(Settings.GPS_ComPort_Baudrate));
            }
            

            //CAM

            //moduleCam.LoadDevices();

            //if (moduleCam.devices.Length > 0)
            //{
            //    moduleCam.AttachToControl(moduleCam.devices[0], pictureBox_Cam);
            //}

            webKitBrowser_Web.Url = new Uri("http://www.google.it");
        }
        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            GpsHandler.Dispose();  //Closes serial port and cleans up
            Application.Exit();
        }
        private void FormMain_ClientSizeChanged(object sender, EventArgs e)
        {
            RenderedScreenImage_ToCompletelyRepaint = true;
        }
        private void FormMain_Move(object sender, EventArgs e)
        {
            RenderedScreenImage_ToCompletelyRepaint = true;
        }

        //Mouse
        private void FormMain_MouseMove(object sender, MouseEventArgs e)
        {

            Skin_Button buttonFound = null;

            foreach (Skin_Button tmpBtn in currentScreen.buttons)
            {
                if (PointContainedInThisRectangle(e.Location, tmpBtn.rectangle))
                {
                    buttonFound = tmpBtn;
                    break;
                }
            }

            if ((null != currentButton_) && ((currentButton_ != buttonFound) || (null == buttonFound)))
                FormMainGraphics.DrawImage(currentScreen.image.off, currentButton_.rectangle, currentButton_.rectangle.Left, currentButton_.rectangle.Top, currentButton_.rectangle.Width, currentButton_.rectangle.Height, GraphicsUnit.Pixel);

            currentButton_ = buttonFound;

            if (null != buttonFound)
                FormMainGraphics.DrawImage(currentScreen.image.on, buttonFound.rectangle, buttonFound.rectangle.Left, buttonFound.rectangle.Top, buttonFound.rectangle.Width, buttonFound.rectangle.Height, GraphicsUnit.Pixel);

            FormMain_Paint(this, null);

        }
        private void FormMain_MouseDown(object sender, MouseEventArgs e)
        {
            mousePressed = true;
            mousePositionOnMouseDown = e.Location;
            timer_ButtonPressed.Start();
        }
        private void FormMain_MouseUp(object sender, MouseEventArgs e)
        {
            if (mousePressed)
            {
                if (currentScreen.Name == "Gps")
                {
                    if (PointContainedInThisRectangle(e.Location, currentScreen.Panel_get("GpsViewport").rectangle))
                    {
                        if (MousePosition.X > e.X)
                            moduleGpsOsm.Move_LEFT();
                        else
                            moduleGpsOsm.Move_RIGHT();

                        if (MousePosition.Y > e.Y)
                            moduleGpsOsm.Move_DOWN();
                        else
                            moduleGpsOsm.Move_UP();
                    }
                }


                foreach (Skin_Button tmpBtn in currentScreen.buttons)
                {
                    if (PointContainedInThisRectangle(e.Location, tmpBtn.rectangle))
                    {
                        DoActionClick(tmpBtn.actionClick);
                        break;
                    }
                }

            }

            mousePressed = false;
        }
        protected override void OnMouseWheel(MouseEventArgs e)
        {
            if (currentScreen.Name == "Gps")
            {
                if (e.Delta > 0)
                    moduleGpsOsm.Zoom_IN();
                else
                    moduleGpsOsm.Zoom_OUT();
            }
        }

        //Paint
        private void FormMain_Paint(object sender, PaintEventArgs e)
        {
            if (RenderedScreenImage_ToCompletelyRepaint)
            {
                FormMainGraphics.DrawImage(currentScreen.image.off, FormMainRectangle);
                RenderedScreenImage_ToCompletelyRepaint = false;
            }

            RenderedScreenImage = new Bitmap(this.Width, this.Height, FormMainGraphics);
            //http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cscon/html/vclrfcodeprintpreviewingformvisualc.asp
        }

        //timers
        private void timerUpdateRadioData_Tick(object sender, EventArgs e)
        {
            Skin_Label label_RadioFrequency = currentScreen.Label_get("label_RadioFrequency");
            Skin_Label label_RadioRdsInfo = currentScreen.Label_get("label_RadioRdsInfo");

            if (moduleRadioSilabs.RDSname != "")
                label_RadioFrequency.Text = moduleRadioSilabs.GetCurrentFrequencyFormatted() + " - " + moduleRadioSilabs.RDSname;
            else
                label_RadioFrequency.Text = moduleRadioSilabs.GetCurrentFrequencyFormatted();

            label_RadioRdsInfo.Text = moduleRadioSilabs.RDSmessage;

            RenderLabel(label_RadioFrequency);
            RenderLabel(label_RadioRdsInfo);

            foreach (Station tmp in moduleRadioSilabs.GetStations())
            {
                if (tmp.id <= 18)
                {
                    Skin_Label label = currentScreen.Label_get("label_Memory" + tmp.id);

                    if (tmp.name.Length <= 8)
                        label.Text = tmp.name;
                    else
                        label.Text = tmp.name.Substring(0, 8);

                    RenderLabel(label);
                }
            }

        }
        private void timer_ButtonPressed_Tick(object sender, EventArgs e)
        {
            if (mousePressed)
            {
                foreach (Skin_Button tmpBtn in currentScreen.buttons)
                {
                    if (PointContainedInThisRectangle(mousePositionOnMouseDown, tmpBtn.rectangle))
                    {
                        DoActionMaintained(tmpBtn.actionMaintained);
                        break;
                    }
                }
            }

            mousePressed = false;
            timer_ButtonPressed.Stop();
        }
        private void timerUpdateGps_Tick(object sender, EventArgs e)
        {
            Skin_Panel panelGpsViewport = currentScreen.Panel_get("GpsViewport");
            moduleGpsOsm.PaintViewport(panelGpsViewport, FormMainGraphics);
        }
        private void timerSystemPerformance_Tick(object sender, EventArgs e)
        {
            Process proc = Process.GetCurrentProcess();
            long valore = proc.PagedMemorySize64 / 1024 / 1024;

            this.Text = "Stone - Used RAM: " + valore + " Mb - " + "GPS render: " + moduleGpsOsm.LastRenderingTime + " - GPS load data: " + moduleGpsOsm.GetLastLoadDataFromDB();
        }

        //Methods
        private void AddMainButtons(Skin_Screen screen)
        {
            Skin_Button buttonExit_Radio = new Skin_Button();
            buttonExit_Radio.rectangle = new Rectangle(662, 411, 76, 67);
            buttonExit_Radio.actionClick = new Skin_Action("Main_Exit");
            screen.Button_Add(buttonExit_Radio);
            Skin_Button buttonRadio_Radio = new Skin_Button();
            buttonRadio_Radio.rectangle = new Rectangle(60, 411, 76, 67);
            buttonRadio_Radio.actionClick = new Skin_Action("Main_Radio");
            screen.Button_Add(buttonRadio_Radio);
            Skin_Button buttonGps_Radio = new Skin_Button();
            buttonGps_Radio.rectangle = new Rectangle(135, 411, 76, 67);
            buttonGps_Radio.actionClick = new Skin_Action("Main_Gps");
            screen.Button_Add(buttonGps_Radio);
            Skin_Button buttonPhone_Radio = new Skin_Button();
            buttonPhone_Radio.rectangle = new Rectangle(210, 411, 76, 67);
            buttonPhone_Radio.actionClick = new Skin_Action("Main_Phone");
            screen.Button_Add(buttonPhone_Radio);
            Skin_Button buttonCam_Radio = new Skin_Button();
            buttonCam_Radio.rectangle = new Rectangle(285, 411, 76, 67);
            buttonCam_Radio.actionClick = new Skin_Action("Main_Cam");
            screen.Button_Add(buttonCam_Radio);
            Skin_Button buttonWeb_Radio = new Skin_Button();
            buttonWeb_Radio.rectangle = new Rectangle(360, 411, 76, 67);
            buttonWeb_Radio.actionClick = new Skin_Action("Main_Web");
            screen.Button_Add(buttonWeb_Radio);
        }
        private void LoadSkin()
        {
            skin = new Skin(Settings.Skins_Path + "\\" + Settings.Skin_Name);

            //##############   Radio  ###################
            Skin_Screen newScreen_Radio = new Skin_Screen(Settings.Skins_Path + "\\" + Settings.Skin_Name, "Radio");

            //Buttons main menu
            AddMainButtons(newScreen_Radio);

            //Buttons radio
            Skin_Button buttonRadio_SeekUp = new Skin_Button();
            buttonRadio_SeekUp.rectangle = new Rectangle(552, 164, 75, 75);
            buttonRadio_SeekUp.actionClick = new Skin_Action("Radio_SeekUp");
            newScreen_Radio.Button_Add(buttonRadio_SeekUp);
            Skin_Button buttonRadio_SeekDown = new Skin_Button();
            buttonRadio_SeekDown.rectangle = new Rectangle(173, 164, 75, 75);
            buttonRadio_SeekDown.actionClick = new Skin_Action("Radio_SeekDown");
            newScreen_Radio.Button_Add(buttonRadio_SeekDown);
            Skin_Button buttonRadio_FreqUp = new Skin_Button();
            buttonRadio_FreqUp.rectangle = new Rectangle(477, 164, 75, 75);
            buttonRadio_FreqUp.actionClick = new Skin_Action("Radio_FrequencyUp");
            newScreen_Radio.Button_Add(buttonRadio_FreqUp);
            Skin_Button buttonRadio_FreqDown = new Skin_Button();
            buttonRadio_FreqDown.rectangle = new Rectangle(251, 164, 75, 75);
            buttonRadio_FreqDown.actionClick = new Skin_Action("Radio_FrequencyDown");
            newScreen_Radio.Button_Add(buttonRadio_FreqDown);
            //Memories

            int left = 57;

            for (int i = 1; i <= 9; i++)
            {
                Skin_Button buttonRadio_Memory = new Skin_Button();
                buttonRadio_Memory.rectangle = new Rectangle(left, 249, 78, 68);
                buttonRadio_Memory.actionClick = new Skin_Action("Radio_Memory" + i);
                buttonRadio_Memory.actionMaintained = new Skin_Action("Radio_MemoryStore" + i);
                newScreen_Radio.Button_Add(buttonRadio_Memory);

                Skin_Button buttonRadio_Memory2 = new Skin_Button();
                buttonRadio_Memory2.rectangle = new Rectangle(left, 316, 78, 68);
                buttonRadio_Memory2.actionClick = new Skin_Action("Radio_Memory" + (i + 9));
                buttonRadio_Memory2.actionMaintained = new Skin_Action("Radio_MemoryStore" + (i + 9));
                newScreen_Radio.Button_Add(buttonRadio_Memory2);

                //Labels
                Skin_Label label = new Skin_Label();
                label.Font = new System.Drawing.Font("Arial", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                label.ForeColor = System.Drawing.Color.White;
                label.rectangle = new Rectangle(left + 14, 289, 60, 16);
                label.Name = "label_Memory" + i;
                label.Text = "";
                label.Alignment.Alignment = StringAlignment.Center;
                newScreen_Radio.Label_Add(label);

                Skin_Label label2 = new Skin_Label();
                label2.Font = new System.Drawing.Font("Arial", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                label2.ForeColor = System.Drawing.Color.White;
                label2.rectangle = new Rectangle(left + 14, 356, 60, 16);
                label2.Name = "label_Memory" + (i + 9);
                label2.Text = "";
                label2.Alignment.Alignment = StringAlignment.Center;
                newScreen_Radio.Label_Add(label2);

                left += 75;
            }

            //Skin_Button buttonRadio_Memory1 = new Skin_Button();
            //buttonRadio_Memory1.rectangle = new Rectangle(59, 250, 78, 66);
            //buttonRadio_Memory1.action = new Skin_Action("Radio_Memory1");
            //newScreen_Radio.Button_Add(buttonRadio_Memory1);

            //Labels
            Skin_Label label_RadioFrequency = new Skin_Label();
            label_RadioFrequency.Font = new System.Drawing.Font("LCD Display Grid", 26.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            label_RadioFrequency.ForeColor = System.Drawing.Color.Gold;
            label_RadioFrequency.rectangle = new Rectangle(23, 45, 753, 40);
            label_RadioFrequency.Name = "label_RadioFrequency";
            label_RadioFrequency.Text = "";
            newScreen_Radio.Label_Add(label_RadioFrequency);

            Skin_Label label_RadioRdsInfo = new Skin_Label();
            label_RadioRdsInfo.Font = new System.Drawing.Font("LCD Display Grid", 16F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            label_RadioRdsInfo.ForeColor = System.Drawing.Color.Gold;
            label_RadioRdsInfo.rectangle = new Rectangle(23, 93, 753, 40);
            label_RadioRdsInfo.Name = "label_RadioRdsInfo";
            label_RadioRdsInfo.Text = "";
            newScreen_Radio.Label_Add(label_RadioRdsInfo);

            skin.Screen_Add(newScreen_Radio);

            //##############   Gps  ###################
            Skin_Screen newScreen_Gps = new Skin_Screen(Settings.Skins_Path + "\\" + Settings.Skin_Name, "Gps");
            AddMainButtons(newScreen_Gps);

            Skin_Panel panelGps_Viewport = new Skin_Panel();
            panelGps_Viewport.rectangle = new Rectangle(14, 14, 786, 394);
            panelGps_Viewport.Name = "GpsViewport";
            newScreen_Gps.Panel_Add(panelGps_Viewport);

            skin.Screen_Add(newScreen_Gps);

            //##############   Phone  ###################
            Skin_Screen newScreen_Phone = new Skin_Screen(Settings.Skins_Path + "\\" + Settings.Skin_Name, "Phone");
            AddMainButtons(newScreen_Phone);
            skin.Screen_Add(newScreen_Phone);

            //##############   Cam  ###################
            Skin_Screen newScreen_Cam = new Skin_Screen(Settings.Skins_Path + "\\" + Settings.Skin_Name, "Cam");
            AddMainButtons(newScreen_Cam);
            skin.Screen_Add(newScreen_Cam);

            //##############   Web  ###################
            Skin_Screen newScreen_Web = new Skin_Screen(Settings.Skins_Path + "\\" + Settings.Skin_Name, "Web");
            AddMainButtons(newScreen_Web);
            skin.Screen_Add(newScreen_Web);

            DoActionClick(new Skin_Action("Main_Gps"));

            //skin = loadSkinDef(Settings.Skin_Current_Path + "\\main.xml");            
        }
        public void saveSkin(string path)
        {
            try
            {
                XmlSerializer s = new XmlSerializer(typeof(Skin));
                TextWriter w = new StreamWriter(path);
                s.Serialize(w, skin);
                w.Close();
            }
            catch (Exception ex)
            {
                Log("saveSkin(\"" + path + "\")" + ex.ToString());
            }
        }
        public Skin loadSkinDef(string path)
        {
            Skin result = null;

            try
            {
                if (File.Exists(path))
                {
                    XmlSerializer s = new XmlSerializer(typeof(Skin));
                    TextReader r = new StreamReader(path);
                    result = (Skin)s.Deserialize(r);
                    r.Close();
                }
            }
            catch (Exception ex)
            {
                Log("loadSkinDef(\"" + path + "\")" + ex.ToString());
            }

            return result;
        }
        private bool PointContainedInThisRectangle(Point point, Rectangle rectangle)
        {
            return rectangle.Contains(point);
        }
        private void DoActionClick(Skin_Action witch)
        {
            //Main MENU
            if (witch.Name == "Main_Exit")
            {
                moduleRadioSilabs.OFF();
                timerUpdateRadioData.Stop();
                timerUpdateGps.Stop();
                this.Close();
            }
            if (witch.Name == "Main_Radio")
            {
                webKitBrowser_Web.Visible = false;
                pictureBox_Cam.Visible = false;
                currentScreen = skin.Screen_get("Radio");
                moduleRadioSilabs.ON();
                timerUpdateGps.Stop();
                timerUpdateRadioData.Start();
            }
            if (witch.Name == "Main_Gps")
            {
                webKitBrowser_Web.Visible = false;
                pictureBox_Cam.Visible = false;
                timerUpdateRadioData.Stop();
                timerUpdateGps.Start();
                currentScreen = skin.Screen_get("Gps");
            }
            if (witch.Name == "Main_Phone")
            {
                webKitBrowser_Web.Visible = false;
                pictureBox_Cam.Visible = false;
                timerUpdateRadioData.Stop();
                timerUpdateGps.Stop();
                currentScreen = skin.Screen_get("Phone");
            }
            if (witch.Name == "Main_Cam")
            {
                webKitBrowser_Web.Visible = false;
                pictureBox_Cam.Visible = true;
                timerUpdateRadioData.Stop();
                timerUpdateGps.Stop();
                currentScreen = skin.Screen_get("Cam");
            }
            if (witch.Name == "Main_Web")
            {
                webKitBrowser_Web.Visible = true;
                pictureBox_Cam.Visible = false;
                timerUpdateRadioData.Stop();
                timerUpdateGps.Stop();
                currentScreen = skin.Screen_get("Web");
            }

            //Radio
            if (witch.Name == "Radio_SeekUp") moduleRadioSilabs.SeekUp();
            if (witch.Name == "Radio_SeekDown") moduleRadioSilabs.SeekDown();
            if (witch.Name == "Radio_FrequencyUp") moduleRadioSilabs.TuneFrequencyUp(10);
            if (witch.Name == "Radio_FrequencyDown") moduleRadioSilabs.TuneFrequencyDown(10);

            if (witch.Name.StartsWith("Radio_Memory"))
            {
                string MemoryNumeber_str = witch.Name.Replace("Radio_Memory", "");
                moduleRadioSilabs.Tune(MemoryNumeber_str);
            }

            //Gps
        }
        private void DoActionMaintained(Skin_Action witch)
        {
            //Radio

            if (witch.Name.StartsWith("Radio_MemoryStore"))
            {
                string MemoryNumeber_str = witch.Name.Replace("Radio_MemoryStore", "");
                moduleRadioSilabs.StoreStation(MemoryNumeber_str, moduleRadioSilabs.RDSname, moduleRadioSilabs.CurrentFrequency);
            }

            //Gps
        }
        private void ApplyScreen()
        {
            //RenderedScreenImage = new Bitmap(currentScreen.image.off, this.Width, this.Height);
            RenderedScreenImage_ToCompletelyRepaint = true;
            //this.Invalidate();
            //FormMainGraphics.DrawImage(RenderedScreenImage, 1, 1, this.Width, this.Height);
        }
        private void DeApplyScreen(Skin_Screen screenToDeApply)
        {
            //foreach (Label tmp in screenToDeApply.labels)
            //{
            //    this.Controls.Remove(tmp);
            //}

            //this.Invalidate();
        }
        private void RenderLabel(Skin_Label labelToRender)
        {
            if (labelToRender.ToRender)
            {
                FormMainGraphics.DrawImage(currentScreen.image.off, labelToRender.rectangle, labelToRender.rectangle.Left, labelToRender.rectangle.Top, labelToRender.rectangle.Width, labelToRender.rectangle.Height, GraphicsUnit.Pixel);
                //FormMainGraphics.FillRectangle(Brushes.Gray, labelToRender.rectangle);
                FormMainGraphics.DrawString(labelToRender.Text, labelToRender.Font, Brushes.White, labelToRender.rectangle, labelToRender.Alignment);
            }
        }
        private void Log(string text)
        {
            File.AppendAllText(Settings.LOG_Path, DateTime.Now.ToString() + " " + text + "\n\r\n\r");
        }

        #region TMP
        //private void LoadPlugins()
        //{
        //    DirectoryInfo PluginsDirectory = new DirectoryInfo(Settings.Plugins_Path);

        //    foreach (DirectoryInfo PluginDirectory in PluginsDirectory.GetDirectories())
        //    {
        //        LoadPlugin(PluginDirectory.FullName + "\\Plugin.dll");                
        //    }
        //}

        //private void LoadPlugin(string p)
        //{
        //    Assembly a = Assembly.LoadFrom(p);
        //    Type[] mytypes = a.GetTypes();
        //    BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);

        //    foreach (Type t in mytypes)
        //    {
        //        MethodInfo[] mi = t.GetMethods(flags);
        //        Object obj = Activator.CreateInstance(t);

        //        foreach (MethodInfo m in mi)
        //        {
        //            m.Invoke(obj, null);
        //        }
        //    }

        //}
        #endregion
    }
}
